/*****************************************************************************/
/*                                                                           */
/*    Domino Operation System Communication Module                           */
/*                                                                           */
/*    Copyright (C) 2007 Laszlo Arvai                                        */
/*                                                                           */
/*    ------------------------------------------------------------------     */
/*    comRFTransmitter - Radio frequency transmitter encoding routines       */
/*****************************************************************************/

///////////////////////////////////////////////////////////////////////////////
// Includes
#include "comRFTransmitter.h"
#include "sysCompiler.h"
#include "drvIOConfig.h"

///////////////////////////////////////////////////////////////////////////////
// Constants
#define RFTX_BUFFER_LENGTH 10
#define RFTX_BIT_BUFFER_LENGTH 12

///////////////////////////////////////////////////////////////////////////////
// Module global variables

// encoding table (DC offset equalized codes)
static dosROM_DATA(dosByte, l_encoding_table)[16] =
{
	0x0B, 0x0D, 0x0E, 0x13, 0x16, 0x19, 0x1A, 0x1C, 0x23, 0x25, 0x26, 0x29, 0x2C, 0x31, 0x32, 0x34
};

static dosByte l_transmit_data_length = 0;
static dosByte l_transmit_position = 0;
static dosByte l_transmit_buffer[RFTX_BUFFER_LENGTH];
static dosWord l_transmit_bit_buffer;
static dosByte l_transmit_bit_buffer_position;

#ifdef RFTX_DUTY_COMPENSATION
static dosByte l_prev_bit = 0;
static dosBool l_compensated = dosFalse;
#endif

///////////////////////////////////////////////////////////////////////////////
// Init RF Transmitter
void comRFTXInit(void)
{
	InitRFTX();
	RFTX(0);
	l_transmit_data_length = 0;
}

///////////////////////////////////////////////////////////////////////////////
// Is transmitter busy
dosBool comRFTXIsBusy(void)
{
	return l_transmit_data_length != 0;
}

///////////////////////////////////////////////////////////////////////////////
// Transmit message
dosBool comRFTXTransmitMessage( comRFMessage* in_message )
{
	dosByte i;
	dosByte checksum;

	// check if transmitter is busy
	if( comRFTXIsBusy() )
		return dosFalse;

	// check length
	if( in_message->Length == 0 || in_message->Length > RFTX_MAX_DATA_LENGTH )
		return dosFalse;

	// copy id+length
	l_transmit_buffer[0] = (in_message->Id << 3) + (in_message->Length - 1);
	checksum = l_transmit_buffer[0];

	// copy data
	for( i = 0; i < in_message->Length; i++ )
	{
		l_transmit_buffer[i+1] = in_message->Data[i];
		checksum += in_message->Data[i];
	}

	l_transmit_buffer[i+1] = checksum;

	// put preamble into the buffer
	l_transmit_bit_buffer = RFTX_PREAMBLE;
	l_transmit_bit_buffer_position = RFTX_BIT_BUFFER_LENGTH;

	// start transmission
	l_transmit_position = 0;
	l_transmit_data_length = in_message->Length + 1 + 1 + 1; // ( data length + 1 ) + id length + checksum

	// prepare message
	return dosTrue;
}

///////////////////////////////////////////////////////////////////////////////
// Interrupt handler
dosWord comRFTXInterruptHandler(void)
{
#ifdef RFTX_DUTY_COMPENSATION
	dosByte current_bit;
#endif

	// check if there is any data to send
	if( l_transmit_data_length == 0 )
		return RFTX_BIT_TIME;

	// next bit
#ifdef RFTX_DUTY_COMPENSATION
	if( !l_compensated )
	{
#endif

	if( l_transmit_bit_buffer_position > 0 )
		l_transmit_bit_buffer_position--;
	else
	{
		// next byte
		if( l_transmit_position < l_transmit_data_length )
		{
			// prepare next byte
			l_transmit_bit_buffer = ((dosWord)(l_encoding_table[(l_transmit_buffer[l_transmit_position] >> 4) & 0x0f])) << 6;
			l_transmit_bit_buffer |= l_encoding_table[l_transmit_buffer[l_transmit_position] & 0x0f];

			l_transmit_position++;
			l_transmit_bit_buffer_position = RFTX_BIT_BUFFER_LENGTH - 1;
		}
		else
		{
			// no more data
			l_transmit_data_length = 0;
			RFTX(0);
			return RFTX_BIT_TIME;
		}
	}

#ifdef RFTX_DUTY_COMPENSATION
	}

	current_bit = ((l_transmit_bit_buffer >> l_transmit_bit_buffer_position) & 1);
	
	if( l_prev_bit == 1 && current_bit == 0 && !l_compensated )
	{
			l_compensated = dosTrue;

#ifdef RFTX_FIRST_BIT_DUTY_COMPENSATION
		if( l_transmit_bit_buffer_position == RFTX_BIT_BUFFER_LENGTH - 2 && l_transmit_position == 0 )
		{
			return RFTX_FIRST_BIT_DUTY_COMPENSATION;
		}
#endif	

		return RFTX_DUTY_COMPENSATION;
	} 

	RFTX( current_bit );

	l_prev_bit = current_bit;

	if( l_compensated )
	{
		l_compensated = dosFalse;

#ifdef RFTX_FIRST_BIT_DUTY_COMPENSATION
		if( l_transmit_bit_buffer_position == RFTX_BIT_BUFFER_LENGTH - 3 && l_transmit_position == 0 )
		{
			return RFTX_BIT_TIME - RFTX_FIRST_BIT_DUTY_COMPENSATION;
		}
#endif
		
		return RFTX_BIT_TIME - RFTX_DUTY_COMPENSATION;
	}
	else
		return RFTX_BIT_TIME;

#else
	RFTX( ((l_transmit_bit_buffer >> l_transmit_bit_buffer_position) & 1) );

	return RFTX_BIT_TIME;
#endif
}
